package cn.zyk.exception;

import com.alibaba.fastjson.*;
import lombok.extern.slf4j.*;
import org.springframework.validation.*;
import org.springframework.web.bind.*;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.*;

/*
 * 全局异常处理器：所有使用@RequestMapping方法
 * @Author ysh
 * @Date 2023/8/1 10:58
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultUtil handle(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        // 收集所有字段错误
        Map<String, String> fieldErrors = result.getFieldErrors().stream()
                .collect(Collectors.toMap(
                        FieldError::getField,        // 字段名
                        FieldError::getDefaultMessage, // 错误信息
                        (existing, replacement) -> existing + "；" + replacement // 处理同字段多个错误
                ));

        // 收集全局错误（如类级别的校验）
        List<String> globalErrors = result.getGlobalErrors().stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.toList());

        HashMap<String, Object> resultMap = new HashMap<String, Object>() {{
            put("fieldErrors", fieldErrors);
            put("globalErrors", globalErrors);
        }};

        log.error("参数校验失败", e);
        // 构建详细的错误响应
        return ResultUtil.fail(
                400, JSONObject.toJSONString(resultMap)
        );
    }


    @ExceptionHandler(BindException.class)
    public ResultUtil handleBindException(BindException e) {
        BindingResult result = e.getBindingResult();

        // 收集字段错误
        Map<String, Object> fieldErrors = result.getFieldErrors().stream()
                .collect(Collectors.toMap(
                        FieldError::getField,
                        error -> {
                            Map<String, Object> errorInfo = new HashMap<>();
                            errorInfo.put("rejectedValue", error.getRejectedValue());
                            errorInfo.put("message", error.getDefaultMessage());
                            return errorInfo;
                        },
                        (existing, replacement) -> existing, // 合并策略（保留第一个错误）
                        LinkedHashMap::new // 保持错误顺序
                ));

        // 收集全局错误
        List<String> globalErrors = result.getGlobalErrors().stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.toList());

        // 构建完整的错误响应
        Map<String, Object> errorDetails = new HashMap<>();
        errorDetails.put("message", "参数格式不正确");
        if (!fieldErrors.isEmpty()) errorDetails.put("fieldErrors", fieldErrors);
        if (!globalErrors.isEmpty()) errorDetails.put("globalErrors", globalErrors);
        log.error("参数绑定失败: {}", errorDetails, e);
        return ResultUtil.fail(400, JSONObject.toJSONString(errorDetails));
    }

    @ExceptionHandler(ServiceException.class)
    public ResultUtil handle(ServiceException e) {
        log.error("业务异常: code={}, msg={}", e.getCode(), e.getMsg());
        return ResultUtil.fail(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(RuntimeException.class)
    public ResultUtil handle(RuntimeException e) {
        log.error("运行时异常", e);
        return ResultUtil.fail(500, e.getMessage());
    }

    /**
     * 全局异常,此处如果不定义则异常会放行,报错控制台不打印
     */
    @ExceptionHandler(Exception.class)
    public ResultUtil handleGlobalException(Exception e) {
        log.error("系统内部错误", e);
        return ResultUtil.fail(500, e.getMessage());
    }
}
